import 'dart:async';

import 'package:aichat_flutter_wallet/kai_print.dart';
import 'package:aichat_flutter_wallet/module_common/network/http_trade.dart';
import 'package:aichat_flutter_wallet/module_common/provider/token_list_provider.dart';
import 'package:flutter/cupertino.dart';
import 'package:lib_database/lib_database.dart';
import 'package:lib_util/log/log.dart';
import 'package:lib_util/utils/utils.dart';
import 'package:lib_web3/lib_solana_web3.dart';

import '../network/rpc.dart';

enum LoadPageState { none, loading, error, empty }

class TokenInfoNotifier with ChangeNotifier {
  Token? _token;
  LoadPageState transactionState = LoadPageState.loading;
  LoadPageState tokenIdState = LoadPageState.loading;
  List<NonFungibleTokenMeta> tokenIdList = [];
  int transactionListPage = 1;
  bool noMoreTransaction = false;
  List<TransactionBean> transactionList = [];
  bool tokenIdsShowList = false;
  StreamSubscription<List>? _streamSubscription;

  Token get token => _token!;
  TokenListNotifier? _tokenListNotifier;
  Timer? _timer;

  setToken(Token t, TokenListNotifier notifier) {
    _token = t;
    _tokenListNotifier = notifier;
    // 刷新交易记录缓存
    refreshLocal(notify: false);
    // 接口获取最新数据
    // refresh();
    refresh().then((value) => _loopPendingTransactions());
  }

  updateToken(Token t) {
    if (t.walletInfoId == _token!.walletInfoId) {
      _token = t;
      notifyListeners();
    }
  }

  updateTranDetails(TransactionBean tran) {
    int index = transactionList.indexWhere((item) => item.txId == tran.txId);
    if (index != -1) {
      transactionList[index] = tran;
      notifyListeners();
    }
  }

  resetTransaction() {
    ObjectBox().transactionModel.resetTransactionList(token);
    transactionList.clear();
    transactionState = LoadPageState.loading;
    notifyListeners();
    refresh();
  }

  insertTransaction(String txId, Token sendToken, String address, String amount, {String? tokenId}) {
    try {
      int time = DateTime.now().millisecondsSinceEpoch ~/ 1000;
      TransactionBean transactionBean = TransactionBean(
          localTokenId: sendToken.id,
          pending: true,
          state: '2',
          txId: txId,
          transactionTime: time,
          from: sendToken.getWalletInfo()!.address,
          to: address,
          amount: amount,
          tokenContractAddress: sendToken.contract,
          tokenId: tokenId);

      ObjectBox().transactionModel.putPendingTransaction(sendToken, transactionBean);
      if (null != _token && _token!.id == sendToken.id) {
        //将Pending中的交易记录加在交易列表
        refreshLocal();
        _loopPendingTransactions();
      }
    } catch (e) {
      kaiPrint('$e');
    }
  }

  _loopPendingTransactions() async {
    if (null != _timer) {
      _timer!.cancel();
      _timer = null;
    }

    if (null == _token) {
      return;
    }
    // 获取pending中数量
    int pCount = ObjectBox().transactionModel.getPaddingTransactionCount(token);
    print('pending transaction:::::: $pCount');
    if (pCount == 0) {
      return;
    }

    _timer = Timer.periodic(const Duration(seconds: 5), (timer) async {
      int pendingTransactionCount = ObjectBox().transactionModel.getPaddingTransactionCount(token);
      Log().d('pending transaction:$pendingTransactionCount');
      try{
        if (pendingTransactionCount == 0) {
          _timer!.cancel();
          _timer = null;
        } else {
          Chain c = token.getChain()!;
          TransactionBean? t = ObjectBox().transactionModel.getFirstPaddingTransaction(token);
          if (null != t) {
            Future<TransactionDetails>? future;
            if (c.type == ChainType.eth) {
              future = RpcClient().ethTransactionDetails(
                  rpc: ObjectBox().nodeInfoModel.getSelectedNodeInfo(c.shortName).url, txHash: t.txId!);
            }
            if(c.type== ChainType.sol){
              final result  = await SolanaWeb3.solTransactionDetail(
                  rpc: ObjectBox().nodeInfoModel.getSelectedNodeInfo(c.shortName).url, txHash: t.txId!);
              future= Future(() => TransactionDetails(
                  gasFee: result['gasFee'],
                  status: int.parse(result['status']),
                  block: result['block'],
                  confirmed: result['confirmed']
              ));
            }

            if (null != future) {
              try {
                TransactionDetails td = await future;
                if (null == td.confirmed || td.confirmed!) {
                  t.pending = false;
                  t.txFee = td.gasFee;
                  t.height = td.block;
                  t.state = td.status.toString();
                  ObjectBox().transactionModel.updatePendingTransactionState(t);
                  if (_tokenListNotifier != null) {
                    _tokenListNotifier!.updateTokenBalance(token).then((val) {
                      updateToken(val);
                    });
                  }
                }
              } catch (e) {
                Config.logger.e(e);
              }
            }
          }

          int pendingTransactionCountAfter = ObjectBox().transactionModel.getPaddingTransactionCount(token);
          if (pendingTransactionCount != pendingTransactionCountAfter) {
            refreshLocal(notify: true);
          }
          if (pendingTransactionCountAfter == 0) {
            _timer?.cancel();
            _timer = null;
            await refresh();
          }
        }
      }catch(e){
        kaiPrint('error :::::::: ${e.toString()}');
      }
    });
  }

  changeTokenIdShowModel() {
    tokenIdsShowList = !tokenIdsShowList;
    notifyListeners();
  }

  refreshLocal({bool notify = true}) {
    transactionList.clear();
    //查询所有本地交易记录，添加到transactionList
    transactionList.addAll(ObjectBox().transactionModel.getTransactionList(token));
    if (transactionList.isNotEmpty) {
      transactionState = LoadPageState.none;
    }
    if (transactionList.isNotEmpty && notify) {
      notifyListeners();
    }
  }

  // Future loadMoreTransactionList() async {
  //   if (transactionState == LoadPageState.loading) {
  //     return;
  //   }
  //
  //   transactionState = LoadPageState.loading;
  //   notifyListeners();
  //
  //   transactionListPage++;
  //   RPCHttp()
  //       .requestTransactionList(token,
  //           page: transactionListPage,
  //           limit: Config.maxStoreTransactionCountForSingleToken,
  //           afterTxId: transactionList.isNotEmpty ? transactionList.last.txId : null)
  //       .then((value) {
  //     transactionState = LoadPageState.none;
  //     if (value.isNotEmpty) {
  //       transactionList.addAll(value);
  //     } else {
  //       noMoreTransaction = true;
  //     }
  //     notifyListeners();
  //   }).onError((error, stackTrace) {
  //     transactionState = LoadPageState.none;
  //     notifyListeners();
  //     // EasyLoading.showError(error.toString());
  //   });
  // }

  Future refresh(
      {bool updateAsset = true,
      bool notify = true,
      int transactionCount = Config.maxStoreTransactionCountForSingleToken}) async {
    Completer completer = Completer();
    if (null != _streamSubscription) {
      await _streamSubscription!.cancel();
      _streamSubscription = null;
    }

    Future<List<TransactionBean>> transactionFuture =
        HttpTradeList().getTokenTradingList(token, limit: transactionCount);

    _streamSubscription = Future.wait([transactionFuture]).asStream().listen((event) {
      List<TransactionBean> transactions = event[0];
      if (transactions.isNotEmpty) {
        ObjectBox().transactionModel.putTransactionListFromServer(token, transactions);
      }
      // if (transactions.length == 0) return;

      refreshLocal(notify: false);

      transactionListPage = 1;
      // _token = ObjectBox().tokenModel.getTokenById(_token!.id);

      transactionState = transactionList.isEmpty ? LoadPageState.empty : LoadPageState.none;

      // Config.logger.d("balance:${_token!.balance}");

      notifyListeners();

      completer.complete();
    });
    return completer.future.timeout(const Duration(seconds: 10), onTimeout: () {
      // EasyLoading.showError(LocaleKeys.qingqiuchaoshi.tr());
      if (null != _streamSubscription) {
        _streamSubscription!.cancel();
        _streamSubscription = null;
      }
      // throw 'request time out';
    });
  }

  updateSingleTokenIdInfo(int index, NonFungibleTokenMeta tokenMeta) {
    tokenIdList[index] = tokenMeta;
    notifyListeners();
  }

  destroy() {
    if (null != _streamSubscription) {
      _streamSubscription!.cancel();
    }
    _streamSubscription = null;
    transactionState = LoadPageState.loading;
    tokenIdState = LoadPageState.loading;
    _token = null;
    tokenIdList.clear();
    transactionListPage = 1;
    noMoreTransaction = false;
    transactionList.clear();
    tokenIdsShowList = false;
    _tokenListNotifier = null;
    if (null != _timer) {
      _timer!.cancel();
      _timer = null;
    }
  }
}
